home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / bs941029.tgz / bbsx-941029.tar / bbsx / udbm.c < prev    next >
C/C++ Source or Header  |  1994-10-29  |  17KB  |  647 lines

  1. #ifndef __lint
  2. static const char rcsid[] = "@(#) $Header: /home/dg1rtf/tcp/bbsx/RCS/udbm.c,v 1.1 1994/06/01 22:21:32 dg1rtf Exp $";
  3. #endif
  4.  
  5. /* User Data Base Manager */
  6.  
  7. #define DEBUG           0
  8.  
  9. #include <sys/types.h>
  10.  
  11. #include <stdio.h>
  12.  
  13. #include <ctype.h>
  14. #include <errno.h>
  15. #include <fcntl.h>
  16. #include <pwd.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <sys/stat.h>
  20. #include <unistd.h>
  21.  
  22. #include "o_bbs.h"
  23. #include "configure.h"
  24.  
  25. struct user {
  26.   struct user *next;
  27.   const char *call;
  28.   const char *name;
  29.   const char *street;
  30.   const char *city;
  31.   const char *qth;
  32.   const char *phone;
  33.   const char *mail;
  34.   char alias;
  35. };
  36.  
  37. #define NUM_USERS 2503
  38.  
  39. #if DEBUG
  40. static char usersfile[] = "users";
  41. static char userstemp[] = "users.tmp";
  42. static char indexfile[] = "index";
  43. static char passfile[]  = "passwd";
  44. static char passtemp[]  = "ptmp";
  45. static char spassfile[] = "spasswd";
  46. static char aliasfile[] = "aliases";
  47. static char aliastemp[] = "aliases.tmp";
  48. #else
  49. static char usersfile[] = "/usr/local/lib/users";
  50. static char userstemp[] = "/usr/local/lib/users.tmp";
  51. static char indexfile[] = WRKDIR "/" INDEXFILE;
  52. static char passfile[]  = "/etc/passwd";
  53. static char passtemp[]  = "/etc/ptmp";
  54. static char spassfile[] = "/.secure/etc/passwd";
  55. static char aliasfile[] = ALIASES_FILE;
  56. static char aliastemp[] = ALIASES_FILE ".tmp";
  57. #endif
  58.  
  59. static const char *lockfile;
  60. static const char *null_string = "";
  61. static long heapsize;
  62. static struct user *users[NUM_USERS];
  63. static struct user null_user;
  64.  
  65. static void terminate(const char *s);
  66. static void *allocate(size_t size);
  67. static int calc_crc(const char *str);
  68. static const char *strsave(const char *s);
  69. static char *strlwc(char *s);
  70. static char *rmspaces(char *s);
  71. static char *strtrim(char *s);
  72. static int is_call(const char *s);
  73. static int is_qth(const char *s);
  74. static int is_phone(const char *s);
  75. static int is_mail(const char *s);
  76. static int join(const char **s1, const char **s2);
  77. static struct user *getup(const char *call, int create);
  78. static FILE *fopenexcl(const char *path);
  79. static void output_line(const struct user *up, FILE *fp);
  80. static int fixusers(void);
  81. static void fixpasswd(void);
  82. static void fixaliases(void);
  83.  
  84. /*---------------------------------------------------------------------------*/
  85.  
  86. static void terminate(const char *s)
  87. {
  88.   perror(s);
  89.   if (lockfile) unlink(lockfile);
  90.   exit(1);
  91. }
  92.  
  93. /*---------------------------------------------------------------------------*/
  94.  
  95. #define uchar(x) ((x) & 0xff)
  96.  
  97. /*---------------------------------------------------------------------------*/
  98.  
  99. static void *allocate(size_t size)
  100. {
  101.  
  102.   static char *freespace;
  103.   static size_t allocsize = 64*1024-2;
  104.   static size_t freesize;
  105.   void * p;
  106.  
  107.   size = (size + 3) & ~3;
  108.   if (size > freesize) {
  109.     for (; ; ) {
  110.       if (size > allocsize) {
  111.     errno = ENOMEM;
  112.     terminate("allocate()");
  113.       }
  114.       if ((freespace = malloc(allocsize)) != NULL) {
  115.     freesize = allocsize;
  116.     heapsize += allocsize;
  117.     break;
  118.       }
  119.       allocsize >>= 1;
  120.     }
  121.   }
  122.   p = freespace;
  123.   freespace += size;
  124.   freesize -= size;
  125.   return p;
  126. }
  127.  
  128. /*---------------------------------------------------------------------------*/
  129.  
  130. /* Calculate crc16 for a null terminated string (used for hashing) */
  131.  
  132. static int calc_crc(const char *str)
  133. {
  134.  
  135.   static const int crc_table[] = {
  136.     0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
  137.     0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
  138.     0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
  139.     0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
  140.     0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
  141.     0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
  142.     0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
  143.     0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
  144.     0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
  145.     0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
  146.     0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
  147.     0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
  148.     0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
  149.     0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
  150.     0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
  151.     0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
  152.     0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
  153.     0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
  154.     0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
  155.     0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
  156.     0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
  157.     0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
  158.     0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
  159.     0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
  160.     0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
  161.     0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
  162.     0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
  163.     0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
  164.     0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
  165.     0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
  166.     0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
  167.     0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
  168.   };
  169.  
  170.   int crc;
  171.  
  172.   crc = 0;
  173.   while (*str)
  174.     crc = ((crc >> 8) & 0xff) ^ crc_table[(crc ^ *str++) & 0xff];
  175.   return crc;
  176. }
  177.  
  178. /*---------------------------------------------------------------------------*/
  179.  
  180. static const char *strsave(const char *s)
  181. {
  182.  
  183. #define NUM_STRINGS 4999
  184.  
  185.   struct strings {
  186.     struct strings *next;
  187.     char s[1];
  188.   };
  189.  
  190.   int hash;
  191.   static struct strings *strings[NUM_STRINGS];
  192.   struct strings *p;
  193.  
  194.   if (!*s) return null_string;
  195.   for (p = strings[hash = ((calc_crc(s) & 0x7fff) % NUM_STRINGS)];
  196.        p && strcmp(s, p->s);
  197.        p = p->next)
  198.     ;
  199.   if (!p) {
  200.     p = allocate(sizeof(struct strings *) + strlen(s) + 1);
  201.     strcpy(p->s, s);
  202.     p->next = strings[hash];
  203.     strings[hash] = p;
  204.   }
  205.   return p->s;
  206. }
  207.  
  208. /*---------------------------------------------------------------------------*/
  209.  
  210. static char *strlwc(char *s)
  211. {
  212.   char *p;
  213.  
  214.   for (p = s; *p; p++)
  215.     if (*p >= 'A' && *p <= 'Z') *p = tolower(*p);
  216.   return s;
  217. }
  218.  
  219. /*---------------------------------------------------------------------------*/
  220.  
  221. static char *rmspaces(char *s)
  222. {
  223.   char *f, *t;
  224.  
  225.   for (f = t = s; *f; f++)
  226.     if (*f != ' ') *t++ = *f;
  227.   *t = 0;
  228.   return s;
  229. }
  230.  
  231. /*---------------------------------------------------------------------------*/
  232.  
  233. static char *strtrim(char *s)
  234. {
  235.   char *p;
  236.  
  237.   for (p = s; *p; p++) ;
  238.   while (--p >= s && *p == ' ') ;
  239.   p[1] = 0;
  240.   return s;
  241. }
  242.  
  243. /*---------------------------------------------------------------------------*/
  244.  
  245. static int is_call(const char *s)
  246. {
  247.   int d, l;
  248.  
  249.   l = strlen(s);
  250.   if (l < 4 || l > 6) return 0;
  251.   if (!isalpha(uchar(s[l-1]))) return 0;
  252.   for (d = 0; *s; s++) {
  253.     if (!isalnum(uchar(*s))) return 0;
  254.     if (isdigit(uchar(*s))) d++;
  255.   }
  256.   return (d >= 1 && d <= 2);
  257. }
  258.  
  259. /*---------------------------------------------------------------------------*/
  260.  
  261. static int is_qth(const char *s)
  262. {
  263.   switch (strlen(s)) {
  264.   case 5:
  265.     if ((s[0] >= 'A' && s[0] <= 'Z' || s[0] >= 'a' && s[0] <= 'z') &&
  266.     (s[1] >= 'A' && s[1] <= 'Z' || s[1] >= 'a' && s[1] <= 'z') &&
  267.     (s[2] >= '0' && s[2] <= '8'                              ) &&
  268.     (s[3] >= '0' && s[3] <= '9'                              ) &&
  269.     (s[4] >= 'A' && s[4] <= 'J' || s[4] >= 'a' && s[4] <= 'j') &&
  270.      s[4] != 'I' && s[4] != 'i')
  271.       return 1;
  272.     break;
  273.   case 6:
  274.     if ((s[0] >= 'A' && s[0] <= 'R' || s[0] >= 'a' && s[0] <= 'r') &&
  275.     (s[1] >= 'A' && s[1] <= 'R' || s[1] >= 'a' && s[1] <= 'r') &&
  276.     (s[2] >= '0' && s[2] <= '9'                              ) &&
  277.     (s[3] >= '0' && s[3] <= '9'                              ) &&
  278.     (s[4] >= 'A' && s[4] <= 'X' || s[4] >= 'a' && s[4] <= 'x') &&
  279.     (s[5] >= 'A' && s[5] <= 'X' || s[5] >= 'a' && s[5] <= 'x'))
  280.       return 1;
  281.     break;
  282.   }
  283.   return 0;
  284. }
  285.  
  286. /*---------------------------------------------------------------------------*/
  287.  
  288. static int is_phone(const char *s)
  289. {
  290.   int slash;
  291.  
  292.   for (slash = 0; *s; s++)
  293.     if (*s == '/')
  294.       slash++;
  295.     else if (!isdigit(uchar(*s)))
  296.       return 0;
  297.   return (slash == 1);
  298. }
  299.  
  300. /*---------------------------------------------------------------------------*/
  301.  
  302. static int is_mail(const char *s)
  303. {
  304.   return (int) (strchr(s, '@') != NULL);
  305. }
  306.  
  307. /*---------------------------------------------------------------------------*/
  308.  
  309. static int join(const char **s1, const char **s2)
  310. {
  311.   if (s1 == s2) return 0;
  312.   if (*s1 == null_string || strstr(*s2, *s1)) {
  313.     *s1 = *s2;
  314.     return 0;
  315.   }
  316.   if (*s2 == null_string || strstr(*s1, *s2)) {
  317.     *s2 = *s1;
  318.     return 0;
  319.   }
  320.   return 1;
  321. }
  322.  
  323. /*---------------------------------------------------------------------------*/
  324.  
  325. static struct user *getup(const char *call, int create)
  326. {
  327.  
  328.   int hash;
  329.   struct user *up;
  330.  
  331.   for (up = users[hash = ((calc_crc(call) & 0x7fff) % NUM_USERS)];
  332.        up && strcmp(call, up->call);
  333.        up = up->next)
  334.     ;
  335.   if (create && !up) {
  336.     up = allocate(sizeof(*up));
  337.     *up = null_user;
  338.     up->call = strsave(call);
  339.     up->next = users[hash];
  340.     users[hash] = up;
  341.   }
  342.   return up;
  343. }
  344.  
  345. /*---------------------------------------------------------------------------*/
  346.  
  347. static FILE *fopenexcl(const char *path)
  348. {
  349.  
  350.   FILE * fp;
  351.   int fd, try;
  352.  
  353.   for (try = 1; ; try++) {
  354.     if ((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644)) >= 0) break;
  355.     if (try >= 10) terminate(path);
  356.     sleep(try);
  357.   }
  358.   lockfile = path;
  359.   fp = fdopen(fd, "w");
  360.   if (!fp) terminate(path);
  361.   return fp;
  362. }
  363.  
  364. /*---------------------------------------------------------------------------*/
  365.  
  366. static void output_line(const struct user *up, FILE *fp)
  367. {
  368.  
  369. #define append(s)                    \
  370.   if (*(s)) {                        \
  371.     if (*line) {                     \
  372.       *t++ = ',';                    \
  373.       *t++ = ' ';                    \
  374.     }                                \
  375.     for (f = (s); *f; *t++ = *f++) ; \
  376.   }
  377.  
  378.   char line[1024];
  379.   const char *f;
  380.   char *t;
  381.  
  382.   t = line;
  383.   *t = 0;
  384.   append(up->call);
  385.   append(up->name);
  386.   append(up->street);
  387.   append(up->city);
  388.   append(up->qth);
  389.   append(up->phone);
  390.   append(up->mail);
  391.   *t = 0;
  392.   fputs(line, fp);
  393.   putc('\n', fp);
  394. }
  395.  
  396. /*---------------------------------------------------------------------------*/
  397.  
  398. static int fixusers(void)
  399. {
  400.  
  401. #define NF 20
  402.  
  403.   FILE *fpi, *fpo;
  404.   char *cp;
  405.   char *f, *t;
  406.   char *field[NF];
  407.   char hostname[1024];
  408.   char line[1024], orig_line[1024], mybbs[1024];
  409.   int errors = 0;
  410.   int i, nf, timestamp;
  411.   struct index index;
  412.   struct user *up;
  413.   struct user user;
  414.  
  415.   if (!(fpi = fopen(usersfile, "r"))) terminate(usersfile);
  416.   fpo = fopenexcl(userstemp);
  417.   while (fgets(line, sizeof(line), fpi)) {
  418.     for (f = line; *f; f++)
  419.       if (isspace(uchar(*f))) *f = ' ';
  420.     for (t = f = line; *f; f++)
  421.       if (*f != ' ' || f[1] != ' ') *t++ = *f;
  422.     if (t > line && t[-1] == ' ') t--;
  423.     *t = 0;
  424.     strcpy(orig_line, line);
  425.     f = line;
  426.     memset((char *) field, 0 , sizeof(field));
  427.     nf = 0;
  428.     user = null_user;
  429.     for (; ; ) {
  430.       while (*f && (*f == ' ' || *f == ',')) f++;
  431.       if (!*f) break;
  432.       field[nf++] = f;
  433.       f = strchr(f, ',');
  434.       if (f)
  435.     *f++ = 0;
  436.       else
  437.     f = "";
  438.       strtrim(field[nf-1]);
  439.     }
  440.     if (!nf) continue;
  441.     for (i = 0; i < NF; i++)
  442.       if (field[i]) {
  443.     if (!*user.call && is_call(field[i])) {
  444.       user.call = strsave(strlwc(field[i]));
  445.       field[i] = NULL;
  446.       nf--;
  447.     } else if (!*user.qth && is_qth(field[i])) {
  448.       user.qth = strsave(strlwc(field[i]));
  449.       field[i] = NULL;
  450.       nf--;
  451.     } else if (!*user.phone && is_phone(field[i])) {
  452.       user.phone = strsave(field[i]);
  453.       field[i] = NULL;
  454.       nf--;
  455.     } else if (!*user.mail && is_mail(field[i])) {
  456.       user.mail = strsave(strlwc(rmspaces(field[i])));
  457.       field[i] = NULL;
  458.       nf--;
  459.     }
  460.       }
  461.     if (nf)
  462.       for (i = 0; i < NF; i++)
  463.     if (field[i]) {
  464.       user.name = strsave(field[i]);
  465.       field[i] = NULL;
  466.       nf--;
  467.       break;
  468.     }
  469.     if (nf >= 2)
  470.       for (i = 0; i < NF; i++)
  471.     if (field[i]) {
  472.       user.street = strsave(field[i]);
  473.       field[i] = NULL;
  474.       nf--;
  475.       break;
  476.     }
  477.     if (nf)
  478.       for (i = 0; i < NF; i++)
  479.     if (field[i]) {
  480.       user.city = strsave(field[i]);
  481.       field[i] = NULL;
  482.       nf--;
  483.       break;
  484.     }
  485.     if (nf) {
  486.       errors++;
  487.       fprintf(stderr, "***** Too many fields *****\n%s\n\n", orig_line);
  488.       fputs(orig_line, fpo);
  489.       putc('\n', fpo);
  490.       continue;
  491.     }
  492.     if (!*user.call) {
  493.       fputs(orig_line, fpo);
  494.       putc('\n', fpo);
  495.       continue;
  496.     }
  497.     up = getup(user.call, 1);
  498.     if (join(&up->name, &user.name)     |
  499.     join(&up->street, &user.street) |
  500.     join(&up->city, &user.city)     |
  501.     join(&up->qth, &user.qth)       |
  502.     join(&up->phone, &user.phone)   |
  503.     join(&up->mail, &user.mail)) {
  504.       errors++;
  505.       fprintf(stderr, "***** Join failed *****\n%s\n\n", orig_line);
  506.       output_line(&user, fpo);
  507.     }
  508.   }
  509.   fclose(fpi);
  510.  
  511.   if ((fpi = fopen(indexfile, "r")) != NULL) {
  512.     while (fread((char *) &index, sizeof(index), 1, fpi))
  513.       if (index.to[0] == 'M' && index.to[1] == 0                 &&
  514.       !strcmp(index.at, "THEBOX")                            &&
  515.       is_call(index.from)                                    &&
  516.       sscanf(index.subject, "%s %d", mybbs, ×tamp) == 2 &&
  517.       is_call(mybbs)) {
  518.     up = getup(strlwc(index.from), 1);
  519.     *line = '@';
  520.     strcpy(line+1, strlwc(mybbs));
  521.     up->mail = strsave(line);
  522.       }
  523.     fclose(fpi);
  524.   }
  525.  
  526.   gethostname(hostname, sizeof(hostname));
  527.   if (cp = strchr(hostname, '.')) *cp = 0;
  528.   if (is_call(hostname)) {
  529.     up = getup(hostname, 1);
  530.     *line = '@';
  531.     strcpy(line + 1, up->call);
  532.     up->mail = strsave(line);
  533.   }
  534.  
  535.   for (i = 0; i < NUM_USERS; i++)
  536.     for (up = users[i]; up; up = up->next) output_line(up, fpo);
  537.   fclose(fpo);
  538.  
  539.   if (rename(userstemp, usersfile)) terminate(usersfile);
  540.   lockfile = NULL;
  541.   return errors;
  542. }
  543.  
  544. /*---------------------------------------------------------------------------*/
  545.  
  546. static void fixpasswd(void)
  547. {
  548.  
  549. #if !(defined __386BSD__ || defined __bsdi__)
  550.  
  551.   FILE * fp;
  552.   int secured = 0;
  553.   struct passwd *pp;
  554.   struct stat statbuf;
  555.   struct user *up;
  556.  
  557. #ifdef __hpux
  558.   if (!stat(spassfile, &statbuf)) secured = 1;
  559. #endif
  560.   fp = fopenexcl(passtemp);
  561.   while ((pp = getpwent()) != NULL) {
  562.     if (is_call(pp->pw_name) &&
  563.     (up = getup(pp->pw_name, 0)) != NULL &&
  564.     *up->name)
  565.       pp->pw_gecos = (char *) up->name;
  566.     if (secured) pp->pw_passwd = "*";
  567.     putpwent(pp, fp);
  568.   }
  569.   endpwent();
  570.   fclose(fp);
  571.   if (rename(passtemp, passfile)) terminate(passfile);
  572.   lockfile = NULL;
  573.  
  574. #endif
  575.  
  576. }
  577.  
  578. /*---------------------------------------------------------------------------*/
  579.  
  580. static void fixaliases(void)
  581. {
  582.  
  583.   FILE *fpi, *fpo;
  584.   char *p;
  585.   char line[1024];
  586.   int i;
  587.   struct user *up;
  588.  
  589.   if (!*aliasfile) return;
  590.   if (!(fpi = fopen(aliasfile, "r"))) terminate(aliasfile);
  591.   fpo = fopenexcl(aliastemp);
  592.   while (fgets(line, sizeof(line), fpi)) {
  593.     if (!strncmp(line, "# Generated", 11)) break;
  594.     fputs(line, fpo);
  595.     if (isspace(uchar(*line))) continue;
  596.     if ((p = strchr(line, '#')) != NULL) *p = 0;
  597.     if (!(p = strchr(line, ':'))) continue;
  598.     while (--p >= line && isspace(uchar(*p))) ;
  599.     p[1] = 0;
  600.     if ((up = getup(line, 0)) != NULL) up->alias = 1;
  601.   }
  602.   fclose(fpi);
  603.   fputs("# Generated aliases\n", fpo);
  604.   for (i = 0; i < NUM_USERS; i++)
  605.     for (up = users[i]; up; up = up->next)
  606.       if (!up->alias && *up->mail)
  607.     if (*up->mail == '@')
  608.       fprintf(fpo, "%s\t\t: %s%s\n", up->call, up->call, up->mail);
  609.     else
  610.       fprintf(fpo, "%s\t\t: %s\n", up->call, up->mail);
  611.   fclose(fpo);
  612.   if (rename(aliastemp, aliasfile)) terminate(aliasfile);
  613.   lockfile = NULL;
  614. }
  615.  
  616. /*---------------------------------------------------------------------------*/
  617.  
  618. int main(void)
  619. {
  620.  
  621.   null_user.next = 0;
  622.   null_user.call = null_string;
  623.   null_user.name = null_string;
  624.   null_user.street = null_string;
  625.   null_user.city = null_string;
  626.   null_user.qth = null_string;
  627.   null_user.phone = null_string;
  628.   null_user.mail = null_string;
  629.   null_user.alias = 0;
  630.  
  631.   umask(022);
  632.   if (!fixusers()) {
  633.     fixpasswd();
  634.     fixaliases();
  635. #if !DEBUG
  636.     if (*NEWALIASES_PROG) system("exec " NEWALIASES_PROG " >/dev/null 2>&1");
  637. #endif
  638.   }
  639.  
  640. #if DEBUG
  641.   fprintf(stderr, "Total heap size = %ld Bytes\n", heapsize);
  642. #endif
  643.  
  644.   return 0;
  645. }
  646.  
  647.